package com.c3w.synchro.common.service;

import com.c3w.synchro.common.bean.Bean;
import com.c3w.synchro.common.dao.BeanDao;
import com.c3w.synchro.common.validation.Validator;
import com.c3w.synchro.common.validation.event.DuplicateBeanException;
import com.c3w.synchro.common.validation.event.ValidationFailedException;
import org.apache.log4j.Logger;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * User: P.Lalonde
 * Date: 09/02/13
 */
public class BeanService<T extends Bean> implements CrudService<T> {
    private final Logger logger = Logger.getLogger(getClass());
    private BeanDao<T> beanDao;
    private Validator<T> beanValidator;

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public T create(T pojo) throws DuplicateBeanException, ValidationFailedException {
        logger.debug("About to create new bean");

        Long id = pojo.getId();

        if (id != null) {
            T bean = get(id);
            if (bean != null) {
                logger.debug("Existing bean found, cannot create twice.");
                throw new DuplicateBeanException(id);
            }
        }

        logger.debug("About to validate user info before creation.");
        beanValidator.validate(pojo);

        logger.debug("Creating bean.");
        beanDao.persist(pojo);

        if (logger.isInfoEnabled()) {
            logger.info("Bean created. [" + pojo + "]");
        }

        return pojo;

    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public List<T> list() {
        logger.debug("Requesting to list all beans.");
        return beanDao.findAll();
    }

    @Override
    public T get(Long primaryKey) {
        if (logger.isDebugEnabled()) {
            logger.debug("Requesting bean details. [" + primaryKey + "]");
        }

        return beanDao.findById(primaryKey);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public T delete(Long primaryKey) {
        if (logger.isDebugEnabled()) {
            logger.debug("Requesting bean deletion. [" + primaryKey + "]");
        }

        T toDelete = get(primaryKey);

        if (toDelete != null) {
            beanDao.remove(toDelete);

            if (logger.isInfoEnabled()) {
                logger.info("Bean deleted. [" + toDelete + "]");
            }
        }

        return toDelete;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public T update(T pojo) {
        logger.debug("Updating bean details.");

        logger.debug("About to validate bean info before update.");
        // TODO validate user

        beanDao.merge(pojo);

        if (logger.isInfoEnabled()) {
            logger.info("Bean updated. [" + pojo + "]");
        }
        return pojo;
    }


    /**
     * Spring injection.
     *
     * @param beanDao Le dao pour la couche d'accès de données.
     */
    public void setBeanDao(BeanDao<T> beanDao) {
        this.beanDao = beanDao;
        logger.info("set bean dao " + beanDao.toString());
    }

    /**
     * Spring injection.
     *
     * @param beanValidator Le validateur de bean.
     */
    public void setBeanValidator(Validator<T> beanValidator) {
        this.beanValidator = beanValidator;
    }
}
